/* 
 * Copyright 2014 Josef Hertl.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package caetus;

import caetus.pkcs11.session.CommandLineOptions;
import caetus.pkcs11.session.Session;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.Provider;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.security.pkcs11.wrapper.PKCS11Exception;

/**
 *
 * @author Josef Hertl
 */
public class TokenInitializer {

    /**
     * Used instead of a file, in order to avoid unnecessary HD accesses
     */
    private String configFile = "name = pkcsTest\nlibrary = ";
    /**
     * The path to the real file (.co) containing the PKCS implementation
     */
    private CommandLineOptions options;
    private char[] pin;
    private String filePath;

    public TokenInitializer(CommandLineOptions commandLineOptions) {
        this.options = commandLineOptions;
        this.filePath = options.getFilePath();
        this.pin = options.getPin();
    }

    /**
     * Decides whether to initialize NSS or just a generic token
     */
    public void initialize() {
        if (options.getNssConfigFile() != null && !options.getNssConfigFile().isEmpty()) {
            initializeNSS();
        } else {
            initializeToken();
        }
    }

    /**
     * Generic software token, including OpenCryptoKi.
     */
    public void initializeToken() {
        if (!filePath.isEmpty()) {
            InputStream in = null;
            try {
                String inputString = configFile + filePath;
                in = new ByteArrayInputStream(inputString.getBytes("UTF-8"));
                Provider p = new sun.security.pkcs11.SunPKCS11(in);
                Session session = new Session(options.getSlot(), filePath, options);
                session.login(pin);
                session.testToken();
                session.closeAndLogout();
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
                System.err.println("The token initialization failed due to: " + ex.getMessage());
            } catch (IOException ex) {
                Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
                System.err.println("The token initialization failed due to: " + ex.getMessage());
            } catch (PKCS11Exception ex) {
                Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
                System.err.println("The token initialization failed due to: " + ex.getMessage());
            } finally {
                try {
                    in.close();
                } catch (IOException ex) {
                    Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public void initializeNSS() {
        InputStream in = null;
        try {
//            String nssConfigFile = "nssLibraryDirectory = /home/josef/DP/Files\nnssDbMode = noDb\nnssModule = keystore\nname = NSS\n";
            String nssConfigFile = readFile(options.getNssConfigFile());
            in = new ByteArrayInputStream(nssConfigFile.getBytes("UTF-8"));
            Provider p = new sun.security.pkcs11.SunPKCS11(in);
            Session session = new Session(options.getSlot(), filePath, options);
            session.testToken();
            session.closeAndLogout();
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("The token initialization failed due to: " + ex.getMessage());
        } catch (IOException ex) {
            System.err.println("The token initialization failed due to: " + ex.getMessage());
            Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (PKCS11Exception ex) {
            System.err.println("The token initialization failed due to: " + ex.getMessage());
            Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(TokenInitializer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private String readFile(String file) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = null;
        StringBuilder stringBuilder = new StringBuilder();
        String ls = System.getProperty("line.separator");

        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    }
}
